package com.beiding.hotcode;

import java.util.HashMap;
import java.util.Map;

/*

    TODO 热编译类同分组下的类比类上下文中的优先级更高

 */
//这里只会静态创建热部署类
public class MyFactory {

    HotCodeConfig hotCodeConfig;

    private boolean hot = true;

    public boolean isHot() {
        return hot;
    }

    public void openHot() {
        hot = true;
    }

    public void closeHot() {
        hot = false;
    }

    public MyFactory(HotCodeConfig hotCodeConfig) {
        this.hotCodeConfig = hotCodeConfig;
    }

    private Map<String, JavaMonitor> monitorMap = new HashMap<>();

    private Map<String, MyPackage> packageMap = new HashMap<>();

    private Map<String, HotClass> staticMap = new HashMap<>();

    //唯一获取
    JavaMonitor getMonitor(String name) {
        JavaMonitor javaMonitor = monitorMap.get(name);
        if (javaMonitor == null) {
            synchronized (MyFactory.class) {
                if ((javaMonitor = monitorMap.get(name)) == null) {
                    javaMonitor = new JavaMonitor(this, name);
                    monitorMap.put(name, javaMonitor);
                }
            }
        }
        return javaMonitor;
    }

    public MyClass getMyClass(String name) {
        if (hot) {
            HotClass hotStatic = staticMap.get(name);
            if (hotStatic == null) {
                synchronized (MyFactory.class) {
                    if ((hotStatic = staticMap.get(name)) == null) {
                        JavaMonitor monitor = getMonitor(name);
                        if (monitor == null) {
                            return null;
                        }
                        hotStatic = new HotClass(monitor);
                        staticMap.put(name, hotStatic);
                    }
                }
            }
            return hotStatic;
        } else {
            try {
                return new RealClass(Class.forName(name));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public MyPackage getPackage(String name) {
        if (hot) {
            MyPackage myPackage = packageMap.get(name);
            if (myPackage == null) {
                synchronized (this) {
                    if ((myPackage = packageMap.get(name)) == null) {
                        myPackage = HotPackage.create(this, name);
                        packageMap.put(name, myPackage);
                    }
                }
            }
            return myPackage;
        } else {
            return new RealPackage(name);
        }
    }

    public ClassGroup createClassGroup() {
        return new ClassGroup(this);
    }

    public PackageGroup createPackageGroup() {
        return PackageGroup.create(this);
    }

}
